package com.demo.study.base.jvm;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 自定义类加载器，双亲委派机制验证
 *
 * @author Baymax
 * @since 2022/6/12
 */
public class MyClassLoadTest {
    public static void main(String[] args) throws Exception {
        String classPath2 = "D:/Project_Code/Advanced_Study/test";
        String className2 = "com.demo.study.base.jvm.Test2VO";
        System.out.println(testMyClassLoader(classPath2, className2)); //com.demo.study.base.jvm.MyClassLoadTest$MyClassLoader

        String classPath = "D:/Project_Code/Advanced_Study/advance.study.parent/advance.study.base/target/classes";
        String className = "com.demo.study.base.jvm.TestVO";
        System.out.println(testMyClassLoader(classPath, className)); //sun.misc.Launcher$AppClassLoader
    }

    private static String testMyClassLoader(String classPath, String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        MyClassLoader classLoader = new MyClassLoader(classPath);
        Class<?> clazz = classLoader.loadClass(className);
        Object testVo = clazz.newInstance();
        Method printMtd = clazz.getDeclaredMethod("print");
        printMtd.invoke(testVo);
        return clazz.getClassLoader().getClass().getName();
    }

    /**
     * 自定义类加载器
     */
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] data = new byte[0];
            try {
                data = loadByte(name);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return defineClass(name, data, 0, data.length);
        }

        private byte[] loadByte(String name) throws IOException {
            name = name.replaceAll("\\.", "/");
            FileInputStream inputStream = new FileInputStream(classPath + "/" + name + ".class");
            int len = inputStream.available();
            byte[] data = new byte[len];
            inputStream.read(data);
            inputStream.close();
            return data;
        }
    }
}
